#pragma once

#include <cstdint>
#include <cstdlib>

namespace plato {

class PlatoStream {
public:
  virtual ~PlatoStream() {}
  virtual auto write(const char *data, std::size_t size) -> std::size_t = 0;
  virtual auto read(char *data, std::size_t size) -> std::size_t = 0;
  virtual auto skip(std::size_t size) -> std::size_t = 0;
  virtual auto copy(char *data, std::size_t size) -> std::size_t = 0;
  virtual auto available() -> std::size_t = 0;
  virtual auto clear() -> void = 0;
  virtual auto data() -> const char * = 0;
  virtual auto operator>>(PlatoStream &stream) -> PlatoStream & = 0;
  virtual auto operator>>(bool &b) -> PlatoStream & = 0;
  virtual auto operator>>(char &c) -> PlatoStream & = 0;
  virtual auto operator>>(unsigned char &c) -> PlatoStream & = 0;
  virtual auto operator>>(std::int16_t &i) -> PlatoStream & = 0;
  virtual auto operator>>(std::int32_t &i) -> PlatoStream & = 0;
  virtual auto operator>>(std::int64_t &i) -> PlatoStream & = 0;
  virtual auto operator>>(std::uint16_t &i) -> PlatoStream & = 0;
  virtual auto operator>>(std::uint32_t &i) -> PlatoStream & = 0;
  virtual auto operator>>(std::uint64_t &i) -> PlatoStream & = 0;
  virtual auto operator>>(float &i) -> PlatoStream & = 0;
  virtual auto operator>>(double &i) -> PlatoStream & = 0;
  virtual auto operator<<(const bool b) -> PlatoStream & = 0;
  virtual auto operator<<(const char c) -> PlatoStream & = 0;
  virtual auto operator<<(const unsigned char c) -> PlatoStream & = 0;
  virtual auto operator<<(const std::int16_t i) -> PlatoStream & = 0;
  virtual auto operator<<(const std::int32_t i) -> PlatoStream & = 0;
  virtual auto operator<<(const std::int64_t i) -> PlatoStream & = 0;
  virtual auto operator<<(const std::uint16_t i) -> PlatoStream & = 0;
  virtual auto operator<<(const std::uint32_t i) -> PlatoStream & = 0;
  virtual auto operator<<(const std::uint64_t i) -> PlatoStream & = 0;
  virtual auto operator<<(const float i) -> PlatoStream & = 0;
  virtual auto operator<<(const double i) -> PlatoStream & = 0;
  virtual auto operator<<(PlatoStream &stream) -> PlatoStream & = 0;
};

} // namespace plato
